package pro.cherish.knowledgesqltool.core.core;


import lombok.extern.slf4j.Slf4j;
import net.sf.jsqlparser.JSQLParserException;
import net.sf.jsqlparser.expression.Expression;
import net.sf.jsqlparser.parser.CCJSqlParserUtil;
import net.sf.jsqlparser.statement.select.*;
import pro.cherish.knowledgesqltool.core.common.ChangeExpression;
import pro.cherish.knowledgesqltool.core.common.CommonConfig;
import pro.cherish.knowledgesqltool.core.common.CommonUtil;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.regex.Pattern;

/**
 * @author 创建人：cherish
 * @version 版本号：V1.0
 * <p>
 * ***************************修订记录************************************
 * 2019-10-11 cherish 创建该类功能。
 * **********************************************************************
 * </p>
 * @ClassName 类名：AbstractJsqlparserTool
 * @Description 功能说明：抽象解析器
 * <p>
 * TODO
 * </p>
 * **********************************************************************
 * @date 创建日期： 2019-10-11 cherish
 */
@Slf4j
public class AbstractJsqlparserTool implements Builder, Parser {

    /**
     * @Description: 获取mybatis可执行的sql模板
     * @Param: [customerSqlTpl, userParamMap]
     * @return: java.lang.String
     * @Author: cherish
     * @Date: 2019/10/11
     */
    public String getMybatisSql(String customerSqlTpl, Map<String, Object> userParamMap) throws JSQLParserException {
        Select select = (Select) CCJSqlParserUtil.parse(customerSqlTpl);
        // where中所有的参数
        List<String> paramNameList = CommonUtil.getParam(customerSqlTpl, Pattern.compile(CommonConfig.getAllParamLabelParanStr()));
        //2、找出没有传递的参数,匹配并清除该sql片段【实则构建该参数，并赋值为null即可】
        paramNameList.stream().forEach(param -> {
            if (!userParamMap.containsKey(param)) {
                userParamMap.put(param, null);
            }
        });
        // 存放所有的片段
        List<Expression> whereExpressionList = new ArrayList<>();
        // 存放所有需要替换的表达式
        List<ChangeExpression> changeExpressionList = new ArrayList<ChangeExpression>();
        // with语句
        List<WithItem> withItemsList = select.getWithItemsList();
        if (withItemsList != null && withItemsList.size() > 0) {
            for (WithItem withItem : withItemsList) {
                SelectBody withItemSelectBody = withItem.getSelectBody();
                if (withItemSelectBody instanceof PlainSelect) {
                    CommonUtil.findWhereFragement(whereExpressionList, withItemSelectBody, changeExpressionList, userParamMap);
                } else if (withItemSelectBody instanceof SetOperationList) {
                    List<SelectBody> selects = ((SetOperationList) withItemSelectBody).getSelects();
                    if (selects != null & selects.size() > 0) {
                        for (SelectBody body : selects) {
                            CommonUtil.findWhereFragement(whereExpressionList, body, changeExpressionList, userParamMap);
                        }
                    }
                }
            }
        }

        // select body
        SelectBody body = select.getSelectBody();
        if (body != null && body instanceof PlainSelect) {
            CommonUtil.findWhereFragement(whereExpressionList, body, changeExpressionList, userParamMap);
        } else if (body != null && body instanceof SetOperationList) {
            List<SelectBody> selects = ((SetOperationList) body).getSelects();
            if (selects != null && selects.size() > 0) {
                for (SelectBody selectBody : selects) {
                    CommonUtil.findWhereFragement(whereExpressionList, selectBody, changeExpressionList, userParamMap);
                }
            }
        }
        String resultSql = CommonUtil.replaceExpressionStr(select.toString(), changeExpressionList);
        String mybatisSql = CommonUtil.adaptMybatisSql(resultSql, userParamMap);
        log.info("最后解析的sql{}", mybatisSql);
        return mybatisSql;
    }

    @Override
    public String buildSql(String sqlTpl, Map<String, Object> params) throws JSQLParserException {
        return null;
    }

    @Override
    public void parserSql() {

    }
}
